import random
import string
import hashlib
from django.http import JsonResponse, HttpResponse
from rest_framework.permissions import AllowAny
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import os
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

captcha_cache = {}


class CaptchaView(APIView):
    authentication_classes = []
    permission_classes = [AllowAny]

    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    def get(self, request):
        session_id = request.GET.get('session_id') or self._generate_session_id()
        length = int(request.GET.get('length', 4))
        code = ''.join(random.choices(string.ascii_letters + string.digits, k=length))

        captcha_cache[session_id] = code.lower()
        print(f"captcha_cache:{captcha_cache}")

        image = self._generate_captcha_image(code)
        response = HttpResponse(content_type='image/png')
        image.save(response, 'PNG')

        response['X-Session-ID'] = session_id
        return response

    def _generate_session_id(self):
        random_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
        return hashlib.sha256(random_str.encode()).hexdigest()[:16]

    def _generate_captcha_image(self, code):
        width, height = 200, 80
        # 创建纯白色背景
        image = Image.new('RGB', (width, height), (255, 255, 255))
        draw = ImageDraw.Draw(image)

        # 加载字体
        fonts = self._get_available_fonts()
        font = self._choose_font(fonts, size=50)

        # 添加少量干扰线
        self._add_simple_noise(draw, width, height)

        # 绘制验证码字符
        self._draw_captcha_text(draw, code, font, width, height, image)

        # 应用轻微模糊，增加真实感
        image = image.filter(ImageFilter.GaussianBlur(radius=0.5))

        return image

    def _get_available_fonts(self):
        """获取可用字体列表"""
        possible_fonts = [
            '/System/Library/Fonts/Supplemental/Arial.ttf',
            '/System/Library/Fonts/PingFang.ttc',
            '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
            '/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf',
            'C:/Windows/Fonts/arial.ttf',
            'C:/Windows/Fonts/simhei.ttf',
        ]
        return [font for font in possible_fonts if os.path.exists(font)]

    def _choose_font(self, fonts, size):
        """选择字体并设置大小"""
        if not fonts:
            return ImageFont.load_default()
        try:
            return ImageFont.truetype(fonts[0], size)
        except:
            return ImageFont.load_default()

    def _add_simple_noise(self, draw, width, height):
        """添加简单干扰线和噪点"""
        # 添加3-5条干扰线
        for _ in range(random.randint(3, 5)):
            color = self._get_random_color(100, 200)
            x1 = random.randint(0, width)
            y1 = random.randint(0, height)
            x2 = random.randint(0, width)
            y2 = random.randint(0, height)
            draw.line((x1, y1, x2, y2), fill=color, width=1)

        # 添加少量噪点
        for _ in range(random.randint(50, 100)):
            draw.point(
                (random.randint(0, width), random.randint(0, height)),
                fill=self._get_random_color(150, 250)
            )

    def _draw_captcha_text(self, draw, code, font, width, height, image):
        """绘制验证码字符"""
        for i, char in enumerate(code):
            # 随机深色
            color = self._get_random_color(30, 100)

            # 计算位置（居中显示）
            spacing = width // (len(code) + 1)
            x = spacing * (i + 1) - 10
            y = (height - font.size) // 2 + random.randint(-5, 5)

            # 随机旋转角度（小范围）
            angle = random.randint(-10, 10)

            # 获取字符尺寸
            bbox = font.getbbox(char)
            char_width = bbox[2] - bbox[0]
            char_height = bbox[3] - bbox[1]

            # 创建字符图像
            char_img = Image.new('RGBA', (char_width, char_height), (0, 0, 0, 0))
            char_draw = ImageDraw.Draw(char_img)
            char_draw.text((-bbox[0], -bbox[1]), char, font=font, fill=color)

            # 旋转字符
            if angle != 0:
                char_img = char_img.rotate(angle, expand=True, fillcolor=(0, 0, 0, 0))

            # 粘贴字符到主图像
            image.paste(char_img, (int(x), int(y)), char_img)

    def _get_random_color(self, min_val, max_val):
        """生成随机颜色"""
        return (
            random.randint(min_val, max_val),
            random.randint(min_val, max_val),
            random.randint(min_val, max_val)
        )

    @staticmethod
    def verify(session_id, user_input):
        if not session_id or not user_input:
            return False

        stored_code = captcha_cache.get(session_id)
        if stored_code and stored_code == user_input.lower():
            del captcha_cache[session_id]
            return True
        return False


class VerifyCaptchaView(APIView):
    authentication_classes = []
    permission_classes = [AllowAny]

    def post(self, request):
        session_id = request.headers.get('X-Session-ID')
        if not session_id:
            return Response(
                {"error": "缺少会话ID"},
                status=status.HTTP_400_BAD_REQUEST
            )

        user_input = request.data.get('captcha')
        if not user_input:
            return Response(
                {"error": "缺少验证码"},
                status=status.HTTP_400_BAD_REQUEST
            )

        is_valid = CaptchaView.verify(session_id, user_input)

        if is_valid:
            return Response(
                {"message": "验证码正确", "valid": True},
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {"message": "验证码错误", "valid": False},
                status=status.HTTP_400_BAD_REQUEST
            )